package indi.zhifa.engine.core.minio.util.impl;

import cn.hutool.core.io.FileUtil;
import indi.zhifa.engine.core.common.crypto.MurmurHash3Util;
import indi.zhifa.engine.core.common.entity.web.ServiceException;
import indi.zhifa.engine.core.common.utils.ContentTypeUtil;
import indi.zhifa.engine.core.common.utils.TimeUtil;
import indi.zhifa.engine.core.minio.properties.MinioConfigProperties;
import indi.zhifa.engine.core.minio.util.IMinIoUtil;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.UUID;

@Slf4j
public class MinIoUtilImpl implements IMinIoUtil {
    static final String URI_DELIMITER = "/";


    private MinioClient mMinioClient;

    private MinioConfigProperties mMinioConfigProperties;

    public MinIoUtilImpl(MinioConfigProperties pMinioConfigProperties, MinioClient pMinioClient) {
        mMinioClient = pMinioClient;
        mMinioConfigProperties = pMinioConfigProperties;
    }


    protected String getFilePath(List<String> pFolder, String pName, String pPrefix) {

        if ((!StringUtils.hasText(pName)) || pName.length() > 50) {
            String uuidName = UUID.randomUUID().toString().replace("-", "");
            pName = uuidName;
        }

        // 防止文件名过长，pName暂定不用
        StringBuilder pathSb = new StringBuilder();

        if(!CollectionUtils.isEmpty(pFolder)) {
            pathSb.append(String.join(URI_DELIMITER, pFolder));
        }
        pathSb.append(URI_DELIMITER).append(pName).append(".").append(pPrefix);

        String path = pathSb.toString();
        return path;
    }


    @Override
    public MinioConfigProperties getConfig() {
        return mMinioConfigProperties;
    }

    @Override
    public String putFile(List<String> pFolder, MultipartFile pFile) {
        String name = pFile.getOriginalFilename();
        String fileName = FileUtil.mainName(name);
        String prefix = FileUtil.extName(name);
        String path = null;
        try {
            path = putFile(pFolder, fileName, prefix, pFile.getInputStream(), pFile.getSize());
        } catch (Exception ex) {
            log.error("获取流时发生错误，错误信息是 ", ex);
            throw new ServiceException("存储数据时发生错误，错误信息是 " + ex);
        }
        return path;
    }

    @Override
    public String putFile(List<String> pFolder, String pName, String pSuffix, InputStream pInputStream, long pSize) {
        String path = getFilePath(pFolder, pName, pSuffix);
        try {
            String contentType = ContentTypeUtil.getContentType(pSuffix);
            mMinioClient.putObject(PutObjectArgs.builder()
                    .stream(pInputStream, pSize, PutObjectArgs.MIN_MULTIPART_SIZE)
                    .object(path)
                    .bucket(mMinioConfigProperties.getBucket())
                    .contentType(contentType)
                    .build());
        } catch (Exception ex) {
            log.error("存储数据时发生错误，错误信息是 ", ex);
            throw new ServiceException("存储数据时发生错误，错误信息是 " + ex);
        }
        return path;
    }

    protected String getFileName(byte[] pBytes) {
        String base64String = MurmurHash3Util.getFileFingerprintBase64(pBytes);;
        return base64String + "|" + TimeUtil.nowStr();
    }

    @Override
    public String putFile(List<String> pFolder, String pSuffix, byte[] pBytes) {
        InputStream is = new ByteArrayInputStream(pBytes);
        String fileName = getFileName(pBytes);
        String rtn = putFile(pFolder, fileName, pSuffix, is, pBytes.length);
        return rtn;
    }


    @Override
    public GetObjectResponse getFile(String pPath) {
        String objectPath = pPath;
        String bucket = mMinioConfigProperties.getBucket();
        if (pPath.startsWith("http") || pPath.startsWith("https")) {
            try {
                URI uri = new URI(pPath);
                bucket = uri.getPath().split("/")[1];  // 获取桶名
                objectPath = uri.getPath().substring(bucket.length() + 2);
            } catch (Exception e) {

            }
        } else if (pPath.startsWith(bucket + "/")) {
            objectPath = pPath.substring(bucket.length() + 2);
        }
        GetObjectResponse getObjectResponse = null;
        try {
            getObjectResponse = mMinioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectPath)
                    .build());
        } catch (Exception ex) {
            log.error("下载文件发生错误，错误信息是 ", ex);
            throw new ServiceException("下载文件发生错误，错误信息是 " + ex);
        }
        return getObjectResponse;
    }

    @Override
    public void deleteFile(String pPath) {
        try {
            mMinioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(mMinioConfigProperties.getBucket())
                    .object(pPath)
                    .build());
        } catch (Exception e) {
            log.error("删除数据时发生错误，错误信息是", e);
            throw new ServiceException("删除数据时发生错误，错误信息是" + e);
        }
    }

    @Override
    public String copy(String pOriginPath, List<String> pDirectory) {
        String orgFileName = StringUtils.getFilename(pOriginPath);
        String suffix = StringUtils.getFilenameExtension(orgFileName);
        String newPath = getFilePath(pDirectory, orgFileName, suffix);
        String bucketName = mMinioConfigProperties.getBucket();

        try {
            mMinioClient.copyObject(CopyObjectArgs.builder()
                    .bucket(bucketName)
                    .source(CopySource.builder().bucket(bucketName).object(pOriginPath).build())
                    .object(newPath)
                    .build());
            return newPath;
        } catch (Exception ex) {
            log.error("拷贝数据时发生错误，错误信息是", ex);
            throw new ServiceException("拷贝数据时发生错误，错误信息是" + ex);
        }
    }
}
